<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "https://www.w3.org/TR/html4/loose.dtd">
<html lang="zh-CN"><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><meta http-equiv="Content-Language" content="zh-CN"><link href="stylesheet.css" media="all" rel="stylesheet" type="text/css">
<title>数据库文件布局</title>
<script> var _hmt = _hmt || []; (function() { var hm = document.createElement("script"); hm.src = "https://hm.baidu.com/hm.js?d286c55b63a3c54a1e43d10d4c203e75"; var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(hm, s); })(); </script>
</head><body class="SECT1">
<div>
<table summary="Header navigation table" width="100%" border="0" cellpadding="0" cellspacing="0">
<tr><th colspan="5" align="center" valign="bottom">PostgreSQL 8.2.3 中文文档</th></tr>
<tr><td width="10%" align="left" valign="top"><a href="storage.html" accesskey="P">后退</a></td><td width="10%" align="left" valign="top"><a href="storage.html">快退</a></td><td width="60%" align="center" valign="bottom">章52. 数据库物理存储</td><td width="10%" align="right" valign="top"><a href="storage.html">快进</a></td><td width="10%" align="right" valign="top"><a href="storage-toast.html" accesskey="N">前进</a></td></tr>
</table>
<hr align="LEFT" width="100%"></div>
<div class="SECT1"><h1 class="SECT1"><a name="STORAGE-FILE-LAYOUT">52.1. 数据库文件布局</a></h1>
<p>本节在文件和目录的层次上描述存储格式。</p>
<p>数据库集群所需要的所有数据都存储在集群的数据目录里，通常用环境变量 <tt class="VARNAME">PGDATA</tt> 来引用。<tt class="VARNAME">PGDATA</tt> 的一个常见值 <tt class="FILENAME">/var/lib/pgsql/data</tt> 。不同服务器管理的多个集群，可以在同一台机器上共存。</p>
<p><tt class="VARNAME">PGDATA</tt> 目录包含几个子目录以及一些控制文件，在<a href="storage-file-layout.html#PGDATA-CONTENTS-TABLE">表52-1</a>里面显示。除了这些必要的东西之外，集群的配置文件 <tt class="FILENAME">postgresql.conf</tt>, <tt class="FILENAME">pg_hba.conf</tt>, <tt class="FILENAME">pg_ident.conf</tt> 通常也都存储在这里(PostgreSQL 8.0 之后也可以把它们放在别的地方)。</p>
<div class="TABLE"><a name="PGDATA-CONTENTS-TABLE"></a>
<p><b>表52-1. <tt class="VARNAME">PGDATA</tt></b> 的内容</p>
<table border="1" class="CALSTABLE"><col><col>
<thead>
<tr><th>Item</th><th>描述</th></tr>
</thead>
<tbody>
<tr><td><tt class="FILENAME">PG_VERSION</tt></td><td>一个包含 PostgreSQL 主版本号的文件</td></tr>
<tr><td><tt class="FILENAME">base</tt></td><td>包含与每个数据库对应的子目录的子目录</td></tr>
<tr><td><tt class="FILENAME">global</tt></td><td>包含集群范围的表的子目录，比如 <tt class="STRUCTNAME">pg_database</tt></td></tr>
<tr><td><tt class="FILENAME">pg_clog</tt></td><td>包含事务提交状态数据的子目录</td></tr>
<tr><td><tt class="FILENAME">pg_multixact</tt></td><td>包含多重事务状态数据的子目录(用于共享的行锁)</td></tr>
<tr><td><tt class="FILENAME">pg_subtrans</tt></td><td>包含子事务状态数据的子目录</td></tr>
<tr><td><tt class="FILENAME">pg_tblspc</tt></td><td>包含指向表空间的符号链接的子目录</td></tr>
<tr><td><tt class="FILENAME">pg_twophase</tt></td><td>包含用于预备事务的状态文件的子目录</td></tr>
<tr><td><tt class="FILENAME">pg_xlog</tt></td><td>包含 WAL(预写日志)文件的子目录</td></tr>
<tr><td><tt class="FILENAME">postmaster.opts</tt></td><td>一个记录服务器最后一次启动时使用的命令行参数的文件</td></tr>
<tr><td><tt class="FILENAME">postmaster.pid</tt></td><td>一个锁文件，记录着当前的服务器主进程 PID 和共享内存段 ID ，在服务器关闭之后此文件就不存在了。</td></tr>
</tbody>
</table>
</div>
<p>对于集群里的每个数据库，在 <tt class="VARNAME">PGDATA</tt><tt class="FILENAME">/base</tt> 里都有对应的一个子目录，子目录的名字是该数据库在 <tt class="STRUCTNAME">pg_database</tt> 里的 OID 。这个子目录是该数据库文件的缺省位置；特别值得一提的是，该数据库的系统表存储在此。</p>
<p>每个表和索引都存储在独立的文件里，以该表或者该索引的 <i class="FIRSTTERM">filenode</i> 号命名，该号码可以在 <tt class="STRUCTNAME">pg_class</tt>.<tt class="STRUCTFIELD">relfilenode</tt> 找到。</p>
<div class="CAUTION">
<table class="CAUTION" border="1" width="100%">
<tr><td align="CENTER"><b>警告</b></td></tr>
<tr><td align="LEFT"><p>请注意，虽然一个表的 filenode 通常和它的 OID 相同，但实际上<span class="emphasis"><i class="EMPHASIS">并不</i></span>必须如此；有些操作，比如 <tt class="COMMAND">TRUNCATE</tt>, <tt class="COMMAND">REINDEX</tt>, <tt class="COMMAND">CLUSTER</tt> 以及一些特殊的 <tt class="COMMAND">ALTER TABLE</tt> 形式，都可以改变 filenode 而同时保留 OID 。不应该假设 filenode 和表 OID 相同。</p></td></tr>
</table>
</div>
<p>在表或者索引超过 1 GB 之后，它就被分裂成 1GB 大小的<i class="FIRSTTERM">段</i>。第一个段的文件名和 filenode 相同；随后的段名名为 filenode.1, filenode.2 ... 等等。这样的安排避免了在某些有文件大小限制的平台上的问题。表和索引的内容在<a href="storage-page-layout.html">节52.3</a>里有进一步讨论。</p>
<p>一个表如果有些字段里面可能存储相当大的数据，那么就会有个相关联的 <i class="FIRSTTERM">TOAST</i> 表，用于存储无法在表的数据行中放置的超大线外数据。如果有的话，<tt class="STRUCTNAME">pg_class</tt>.<tt class="STRUCTFIELD">reltoastrelid</tt> 从一个表链接到它的 TOAST 表。参阅<a href="storage-toast.html">节52.2</a>获取更多信息。</p>
<p>表空间把情况搞得更复杂些。每个用户定义的表空间都在 <tt class="VARNAME">PGDATA</tt><tt class="FILENAME">/pg_tblspc</tt> 目录里面有一个符号连接，它指向物理的表空间目录(就是在 <tt class="COMMAND">CREATE TABLESPACE</tt> 命令里声明的那个目录)。这个符号连接是用表空间的 OID 命名的。在物理表空间里面包含多个子目录，每个子目录对应着一个在这个表空间里有元素的数据库，并且该子目录以那个数据库的 OID 命名。该目录里的表遵循 filenode 的命名规则。<tt class="LITERAL">pg_default</tt> 没有通过 <tt class="FILENAME">pg_tblspc</tt> 关联，但是对应 <tt class="VARNAME">PGDATA</tt><tt class="FILENAME">/base</tt> 。类似的还有，<tt class="LITERAL">pg_global</tt> 没有通过 <tt class="FILENAME">pg_tblspc</tt> 关联，而是对应 <tt class="VARNAME">PGDATA</tt><tt class="FILENAME">/global</tt> 。</p>
</div>
<div>
<hr align="LEFT" width="100%">
<table summary="Footer navigation table" width="100%" border="0" cellpadding="0" cellspacing="0">
<tr><td width="33%" align="left" valign="top"><a href="storage.html" accesskey="P">后退</a></td><td width="34%" align="center" valign="top"><a href="index.html" accesskey="H">首页</a></td><td width="33%" align="right" valign="top"><a href="storage-toast.html" accesskey="N">前进</a></td></tr>
<tr><td width="33%" align="left" valign="top">数据库物理存储</td><td width="34%" align="center" valign="top"><a href="storage.html" accesskey="U">上一级</a></td><td width="33%" align="right" valign="top">TOAST</td></tr>
</table>
</div>
</body></html>